Feat/stereo saving - #204
Merged
Merged
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #204 +/- ##
=======================================
Coverage 93.08% 93.08%
=======================================
Files 58 58
Lines 10337 10366 +29
=======================================
+ Hits 9622 9649 +27
- Misses 504 505 +1
- Partials 211 212 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
FrantaBOT
approved these changes
Aug 12, 2026
thomas-vilte
force-pushed
the
feat/stereo-saving
branch
from
August 13, 2026 16:42
9e761ea to
2231abb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The stereo-saving term from
compute_vbrwas missing. Bands encoded with intensity stereo carry the shape of a single channel, so the frame needs fewer bits as the two channels become more redundant (celt_encoder.c):The value comes from alloc_trim_analysis, which already calculates inter-channel correlation for the lower 8 bands. What was missing was minXC — the weakest correlation across the bands coded with intensity stereo — and the accumulated state:
A single decorrelated band in that range is enough to prevent mid/side from saving bits, regardless of how redundant the lower bands are.
I also reordered the calculations to match the reference: libopus determines the intensity band before the trim and VBR target, since both depend on it (celt_encoder.c:2404). pion was calculating it after both, and in VBR it was therefore derived from the post-VBR frame size instead of the nominal bitrate. That happened to produce the same result in CBR, but not in VBR.
Measurement
Average packet size over music, compared against libopus at the same requested bitrate:
The important part here is that without this term, pion was spending 4–6% more bits than the reference at the lower bitrates. That means the VBR quality comparisons we were making before were at different actual bitrates and therefore favored pion unfairly.
With the rates matched, round-trip SNR against libopus is:
So the SNR number gets worse at two of the three rates, but the behavior is correct: the encoder is now actually delivering the bitrate the user requested. The −0.14 to −0.22 dB is the real gap we had been hiding with the extra bits.
CBR is unchanged, verified at 24, 48, and 96 kb/s: +0.014 / +0.015 / −0.002 dB, identical to before this change.
What is still missing from VBR
With the actual rates now matched, the remaining gap is around −0.14 to −0.22 dB.
The remaining compute_vbr terms are:
Tonality boost, which requires analysis.c. temporal_vbr, which is portable. Its factor is 0.0000031 * max(0, min(32000, 96000-bitrate)), so it is zero at 96 kb/s and can only affect the lower bitrates.
Reference issue
Part of #34.